home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Languguage OS 2
/
Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO
/
a_utils
/
decomp.lha
/
decomp
/
tables.c
< prev
next >
Wrap
C/C++ Source or Header
|
1988-01-12
|
7KB
|
364 lines
/*
* Module: tables.c
*
* Author: J. Reuter
*
* The functions in this module are used to make the first pass over
* a functions code and add information to the symbol and label tables.
*/
#include "defs.h"
#include "machine.h"
#include "labeltab.h"
#include "objfile.h"
#include "vartab.h"
/*
* The tables() function makes a pass through a function's code.
* While processing the code, it builds several tables. These
* include register and automatic (stack) local variable usage,
* branch targets (for building basic blocks), and global symbol
* usage (to determine type).
*/
tables( addr, end_addr )
address addr, end_addr;
{
unsigned char ins;
address insaddr;
unsigned char mode;
register int argtype, amode, argno, argval;
register int rn, type, fl;
short offset;
struct nlist *s;
struct relocation_info *r;
/* initialize pass */
relo_first();
r = relo_next();
/* loop across all the instructions in this function */
while ( addr < end_addr ) {
argval = 0;
ins = get_byte( addr );
addr += 1;
/* process all the operands for the instruction */
for (argno = 0; argno < opcode[ins].numargs; argno++) {
argtype = opcode[ins].argtype[argno];
if (is_branch_disp(argtype)) {
mode = 0xAF + ( (typelen(argtype) & ~T_UNSIGNED) << 4);
} else {
mode = get_byte( addr );
addr += 1;
}
while ( r != NULL && addr > r->r_address )
r = relo_next();
rn = regnm( mode );
type = typelen( argtype );
amode = addrmode( mode );
fl = 0;
if ( acctype( argtype ) == ACCW || acctype( argtype ) == ACCM )
fl |= C_WRITTEN;
if ( type & T_UNSIGNED )
fl |= T_UNSIGNED;
if ( r != NULL && addr == r->r_address ) {
if ( amode == LONGDISP || amode == LONGDISPDEF ) {
argval = getdisp(addr, 4, rn, amode);
addr += 4;
} else if ( amode == AUTOINC ) {
if ( rn != PC ) {
fprintf( stderr, "ERR: strange relo autoinc reg\n" );
} else {
/* immediate values */
switch ( type & ~T_UNSIGNED ) {
case TYPL:
argval = getdisp(addr, 4, rn, amode);
addr += 4;
break;
default:
fprintf( stderr, "ERR: strange relo autoinc %d\n",
type );
break;
}
}
} else {
fprintf( stderr, "ERR: bad relo mode %d\n", amode );
}
if ( r->r_extern ) {
s = &symtab[r->r_symbolnum];
if ( s->n_type == (N_EXT+N_UNDF) ) {
if ( amode == LONGDISP || amode == AUTOINC ) {
reg_add( rn, T_LONG, 0 );
ext_add( r->r_symbolnum, type, argval, fl );
} else if ( amode == LONGDISPDEF ) {
reg_add( rn, T_LONG, 0 );
ext_add( r->r_symbolnum, type | T_POINTER,
argval, fl );
} else {
fprintf( stderr, "ERR: ext relo mode %d\n", amode );
}
} else {
fprintf( stderr, "ERR: ext relo type %d\n", s->n_type );
}
} else { /* not r->r_extern */
if ( amode == LONGDISP || amode == LONGDISPDEF ) {
if ( amode == LONGDISPDEF )
type |= T_POINTER;
if ( rn == PC ) {
switch ( r->r_symbolnum ) {
case 4:
/* static function */
int_add( argval, type, C_STATIC, C_TEXT );
break;
case 5:
/* global function */
int_add( argval, type, 0, C_TEXT );
break;
case 6:
/* static data, const, string */
int_add( argval, type, C_STATIC+fl, C_DATA );
break;
case 7:
/* global data, const, string */
int_add( argval, type, fl, C_DATA );
break;
case 8:
/* static bss */
int_add( argval, type, C_STATIC+fl, C_BSS );
break;
default:
fprintf( stderr, "ERR: bad relo symbolnum %d\n",
r->r_symbolnum );
break;
}
} else {
/* other registers? */
}
} else if ( amode == AUTOINC ) {
switch ( r->r_symbolnum ) {
case 6:
/* static data */
int_add( argval, type, C_STATIC+fl, C_DATA );
break;
case 8:
/* static bss */
int_add( argval, type, C_STATIC+fl, C_BSS );
break;
default:
fprintf( stderr, "ERR: auto relo symnum %d\n",
r->r_symbolnum );
break;
}
} else {
fprintf( stderr, "ERR: int relo mode %d\n", amode );
}
}
} else { /* no relo info */
switch (amode) {
case LITSHORT:
case LITUPTO31:
case LITUPTO47:
case LITUPTO63:
argval = mode;
break;
case INDEX:
reg_add( rn, T_LONG, 0 );
argno--;
break;
case REG:
reg_add( rn, type, fl );
break;
case REGDEF:
reg_add( rn, type | T_POINTER, 0 );
break;
case AUTODEC:
reg_add( rn, type | T_POINTER, 0 );
break;
case AUTOINC:
if ( rn != PC ) {
reg_add( rn, type | T_POINTER, 0 );
} else {
/* immediate values */
switch ( type & ~T_UNSIGNED ) {
case TYPB:
argval = getdisp(addr, 1, rn, amode);
addr += 1;
break;
case TYPW:
argval = getdisp(addr, 2, rn, amode);
addr += 2;
break;
case TYPL:
argval = getdisp(addr, 4, rn, amode);
addr += 4;
break;
default:
printf( "ERR: strange-autoinc %d\n", type );
break;
}
}
break;
case AUTOINCDEF:
if ( rn == PC ) {
/* immediate deferred */
argval = getdisp(addr, 4, rn, amode);
addr += 4;
} else {
reg_add( rn, type | T_POINTER, 0 );
}
break;
case BYTEDISP:
argval = getdisp(addr, 1, rn, amode);
regdisp( rn, argval, type, fl );
addr += 1;
break;
case BYTEDISPDEF:
argval = getdisp(addr, 1, rn, amode);
regdisp( rn, argval, type, fl );
addr += 1;
break;
case WORDDISP:
argval = getdisp(addr, 2, rn, amode);
regdisp( rn, argval, type, fl );
addr += 2;
break;
case WORDDISPDEF:
argval = getdisp(addr, 2, rn, amode);
regdisp( rn, argval, type, fl );
addr += 2;
break;
case LONGDISP:
argval = getdisp(addr, 4, rn, amode);
regdisp( rn, argval, type, fl );
addr += 4;
break;
case LONGDISPDEF:
argval = getdisp(addr, 4, rn, amode);
regdisp( rn, argval, type, fl );
addr += 4;
break;
}
if ( is_branch_disp( argtype ) )
llb_add( argval, FALSE );
}
}
if (ins == O_CASEB || ins == O_CASEW || ins == O_CASEL) {
insaddr = addr;
for (argno = 0; argno <= argval; argno++) {
offset = get_word( addr );
addr += 2;
llb_add( insaddr+offset, TRUE );
}
}
}
}
/*
* Get the displacement of an instruction that uses displacement
* addressing.
*/
static int
getdisp(addr, nbytes, rn, mode)
address addr;
int nbytes;
int rn;
int mode;
{
int argval;
switch (nbytes) {
case 1:
argval = get_byte( addr );
break;
case 2:
argval = get_word( addr );
break;
case 4:
argval = get_long( addr );
break;
}
if (rn == PC && mode >= BYTEDISP) {
argval += addr + nbytes;
}
return argval;
}
static
regdisp( rn, offset, type, fl )
int rn, offset, type, fl;
{
switch ( rn ) {
/* arguments */
case AP:
if ( offset < 0 )
fprintf( stderr, "bad argument offset %d\n", offset );
else
arg_add( offset, type, fl );
break;
/* locals */
case FP:
if ( offset > 0 )
fprintf( stderr, "bad local offset %d\n", offset );
else
loc_add( -offset, type, fl );
break;
case PC:
/* do nothing */
break;
/* everything else */
default:
reg_add( rn, type | T_POINTER, 0 );
break;
}
}